1、your react app suddenly becomes slow after adding new features, how do you find and fix the issue?

可以这样类比来想:think of it like you phone is slowing down after you install too many apps, you need to find out which app is using the resourses and is making you phone slow.

1、we can use chrome devtools, and in the performance tab, and see what is taking the most time.

2、we can use react devtools chrome extension, we can track unneccessary rerenders or infinite loop of rerenders.

3、we can use React.memo and useCallback to making app fast and tracking where is slow.

4、I will check if there are any large amount of data to render at once. usually we render only the visible amount of data, use packages like react.window or react.virtulized.

5、avoid inline functions and objects。

Inline functions and objects are recreated on every render, which can cause child components to re-render unnecessarily — especially if those children depend on referential equality (React.memo, dependency arrays, etc.).

Example problem:

Every render:

So Child thinks props changed → re-renders every time, even if nothing actually changed.

How to fix it:

①Use useCallback for functions

②Use useMemo for objects/arrays

上面这个说法过时了,avoid inline functions and objects说的太绝对了。但我还是把它保留,因为这个说法很流行。

在现代 React 开发中,“绝对禁止内联函数”被认为是一种过度优化(Over-optimization)。面试时,如果你能辩证地看待这个问题,会显得你更有经验。

以下是针对这个问题的深度解析,以及如何在面试中“专业地反驳”或补充:

  1. 为什么会有“避免内联函数”的说法?

这个观点的核心担忧是 引用相等性(Reference Equality)

  1. 为什么这种说法“不准确”?
  1. 面试时的“标准标准回答” (The "Senior" Answer)

当面试官提到“避免内联函数”时,你可以这样回答:

中文逻辑:

“‘避免内联函数’这个原则在 React 中需要视情况而定

它的主要目的是为了保持引用稳定。如果一个内联函数被传递给了包裹了 React.memo 的子组件,或者作为 useEffect 的依赖项,那么内联函数确实会导致不必要的重绘或 Effect 的重复执行。

但是,对于原生 HTML 标签,或者没有性能瓶颈的普通组件,内联函数是完全可以接受的。过度使用 useCallback 反而会增加代码复杂度。

所以我的原则是:先编写简洁的内联代码,只有在 Profiler 检测到性能瓶颈,或者需要保持引用一致性时,才去使用 useCallback 优化。

  1. 英文面试版本 (Pro Interview Version)

"The advice to avoid inline functions is not an absolute rule; it's about managing reference stability.

The real issue isn't the creation of the function itself—React handles that very efficiently. The issue is that a new function reference can break memoization in child components (using React.memo) or trigger unnecessary useEffect calls.

If I'm passing a function to a native element like a <button>, an inline function is perfectly fine. However, if I'm passing it to a heavy, memoized component, I would wrap it in useCallback to ensure the child doesn't re-render unless its actual logic changes.

My philosophy is: Don't prematurely optimize. I prefer clean, readable code with inline functions first, and only optimize when the Profiler shows a real performance bottleneck."

 

上面的步骤要理解,然后简要的答案先说出来:

When my React app becomes slow after adding new features, I usually debug it in a few steps.

First, I try to measure the problem. I use React DevTools Profiler to see which components are re-rendering too often or taking too long to render.

 

Then I look for the common cause, which is unnecessary re-renders. For example, sometimes new features introduce inline functions or objects in props, which causes child components to re-render even if they are wrapped with React.memo.

In those cases, I might use useCallback or useMemo to keep the references stable. But I don’t just add them everywhere — I only use them when I really see a performance issue.

 

After that, I also check the component structure. Sometimes the problem is that the state is placed too high in the tree, so a small change causes a lot of components to re-render. In that case, I try to move state closer to where it’s used, or split components to isolate updates.

For UI-heavy cases, like big lists, I use techniques like windowing or virtualization to only render what’s visible on the screen. And sometimes I use code splitting to reduce the initial load.

Overall, I try to find the real cause first, and then apply the simplest fix instead of over-optimizing.

 

 

 

2、how do you prevent a login page from being accessible after the user is logged in?

The general idea is:If the user is already authenticated, redirect them away from the login page.

  1. Using React Router (most common)

You check the auth state, and if the user is logged in, redirect them:

Explanation:

This ensures the login page is never visible to authenticated users.

  1. With a Protected Route Wrapper

Sometimes I create a wrapper:

Then wrap the route:

  1. Server-side check (if SSR or backend routing)

If the backend renders the page, the server can also redirect if the session exists.

理解上面的内容后,简要回答:

I prevent the login page from being accessible after login by checking whether the user is authenticated. If the user is already logged in, I immediately redirect them to a protected page like the dashboard. In React Router, this usually means returning a <Navigate> component when user exists. This ensures the login page is only visible to unauthenticated users.

3、how do you handle API errors gracefully in the UI?

  1. Show a clear, user-friendly message

Users should never see raw server errors like “500 Internal Server Error”.

Example:

This keeps the UI clean and understandable.

  1. Use try/catch around API calls

In React components or services:

Then the UI reacts to that error state.

  1. Display fallback UI

For example:

  1. Handle different error types

I often show different messages depending on the error:

This makes the UI feel professional and predictable.

  1. If using React Query

React Query makes this much easier:

React Query automatically gives:

So the UI can handle errors more gracefully.

理解上面之后,简要的回答:

I usually handle API errors in a few simple ways.

First, I wrap API calls in try/catch, or I use tools like React Query, which already gives me error and isError states.

When an error happens, I store it in state and show a friendly message in the UI. For example, I might show “Something went wrong” or display a toast message. I can also give users a retry button so they can try again.

 

For different HTTP errors, I handle them differently. For example, if it’s 401, I redirect the user to the login page. If it’s 403, I show an “access denied” message. If it’s a validation error like 400, I show the message near the form field.

 

For serious cases, I also use an error boundary in React, so if a component crashes, it won’t break the whole page.

And for temporary network issues, I usually just retry the request a few times automatically, or let the user click retry manually.

I also log errors so I can debug them later.

4、a component is fetching the same data multiple times unneccessarily. How do you fix it?

  1. Fix the useEffect dependency array

One of the most common causes is a missing or incorrect dependency array:

❌ Bad (fetch runs every render)

✅ Good (runs only once on mount)

Or if dependencies are required, ensure they don’t change on every render.

  1. Memoize functions with useCallback

If the fetch function is declared inline and passed to children or used inside effects, it may be recreated every render, causing repeated calls.

❌ Bad

✅ Good

  1. Memoize computed values with useMemo

If parameters for your fetch are created inline (like an object), the reference changes every time:

✔️

  1. Lift state up (avoid fetching in many components)

Sometimes multiple sibling components fetch the same data.

Solution:

This way the data is fetched once and shared.

  1. Use a data-fetching library (React Query)

Tools like React Query automatically:

React Query example:

Duplicate calls are automatically prevented.

  1. Ensure no conditional renders cause re-mounting

Some developers accidentally remount a component repeatedly:

If isOpen toggles repeatedly, the component unmounts and remounts, triggering useEffect again.

Fix:

理解上面的内容后,简要的回答:

First, I check the useEffect dependency array — missing or unstable dependencies often cause repeated fetch calls. Then I make sure the fetch function is memoized with useCallback and any params with useMemo, so they don’t change every render. If several components need the same data, I move the fetching logic into a global store, such as zustand, so the data is fetched once and reused everywhere. For even more control, I use libraries like React Query, which provide request deduplication, caching, and stale-while-revalidate behavior out of the box.

 

In short: stabilize dependencies, avoid remounting, and centralize or cache the data so it only gets fetched once.

5、how do you optimize bundle size in a large react app?

可以这样想:think of this like you are travelling, you don't take your complete cupboard or wardrobe with you, you take neccessary some part of it in the travel.

Just like that, whenever you writing thousands of files in your app, you don't need to ship everything to the production.So you need to bundle it and organize it somehow so that it will take minimum size on the user's device and it will be efficient for the performance.

  1. Code splitting → use React.lazy or Suspense
  2. Tree Shaking → use vite or webpack to remove unused imports
  3. Dynamic imports → use dynamic imports, import() to avoid some code to be bundled in the main chunk
  4. Compress assets → images or fonts

理解了上面的内容之后,简要回答:

I usually focus on three things to optimize bundle size: loading less code, removing unnecessary dependencies, and checking the bundle regularly.

First, I use code splitting. For example, I split routes using React.lazy and Suspense, so users only load the code for the page they are actually visiting. For heavier features, I also use dynamic imports so they are loaded only when needed.

 

Then I look at dependencies. I use tools like Webpack Bundle Analyzer or Vite bundle analysis to see what is taking up space. If I find a big library that is not fully needed, I either replace it with a lighter one or import only the parts I use instead of the whole package.

 

After that, I make sure the build is optimized. Things like tree-shaking, minification, and removing dead code are usually handled by the build tool, but I double-check that everything is working correctly and I’m not accidentally importing large modules.

 

For static assets, I also try to keep them lightweight. For example, I prefer SVGs over PNGs when possible, and I use CDN or compression for images.

Overall, my approach is pretty simple: split what can be lazy-loaded, remove what I don’t need, and keep checking the bundle size over time.

6、how do you handle a form with 20+ fields efficiently?

当面试官问large forms,他们想要看到你是否能够优化form、维持状态的能力。

这是Shubham Kulkarni | Coding and Interviews这位老师的回答要点。

1、use form management library like react hook form,

2、structure the form to logical steps or sections.

3、use controlled components,

4、use zod library to validate.

 

下面是chatgpt的回答:

✅ 1. Group related fields into logical sections

Don’t treat 20 fields as 20 individual states. Instead, think of your form as sections:

This gives you:

✔ Better UI/UX ✔ Smaller components ✔ Cleaner validation

Example structure:

✅ 2. Use a form library — don’t manage 20 states manually

Best option: React Hook Form (RHF)

It handles:

For 20+ fields, RHF is definitely better than useState or even Formik.

Example:

✅ 3. Store all form values in one place (not 20 states)

For large forms, do NOT use:

Instead:

Or if using useState manually:

✅ 4. Extract repeating field logic into reusable components

If many fields share:

Create a component:

Now your form becomes:

✅ 5. Use zod to avoid manual checks

With 20+ fields, writing if (!name) error... everywhere becomes painful.

Use Zod:

Integrate with RHF:

Now all validation is centralized and reusable.

✅ 6. Use dynamic generation (optional but powerful)

If fields share patterns, define them as config:

Render automatically:

Great for 20–100 fields.

✅ 7. Split the form into tabs or steps if possible

For UX improvement:

Use a stepper or wizard.

Better:

✔ Less intimidating ✔ Faster rendering ✔ Validation per step

✅ 8. Memoize heavy components

For example, expensive dropdowns.

RHF already minimizes re-renders, but memoization helps further.

🧪 9. For huge forms → Use RHF + Suspense + lazy-loaded sections

If your sections are large:

Better performance for enterprise apps.

理解上面的内容之后,就可以背诵答案了:

When I deal with a large form that has 20+ fields, I mainly focus on keeping it manageable and avoiding unnecessary re-renders.

 

First, I usually split the form into smaller sections, like grouping related fields into separate components. This makes both the code and the UI easier to handle.

 

For state management, I prefer using React Hook Form instead of managing everything with useState. It keeps the form state centralized and avoids a lot of re-render issues, which becomes important when the form gets large.

 

For validation, I typically use a schema-based solution like Zod, so all the validation rules are defined in one place and stay consistent with TypeScript types.

 

If the form has repeated patterns, I also try to create reusable input components or even generate fields from a config object to reduce boilerplate.

 

And from a UX perspective, if the form feels too long, I would split it into multiple steps or tabs, so users don’t feel overwhelmed.

 

So overall, I try to keep it simple: split the form, centralize state, and reuse as much logic and UI as possible.

 

7、your react app needs to support dark mode.How do you implement it?

面试管想听到的要点就是:the theme state should be global, so whenever you toggle the theme at the global state, it will be auto reflected in the children level.

1、I will check whether the dark mode is user preference based or system based.

2、if it's system based.I will use prefers-color-scheme media query to detect system preference on first load.then set the theme mode.

3、if it's user mode, I often rely on react context or redux to set global state, and rely on CSS variables or tailwindcss to set dark mode.

简要回答:

To implement dark mode in a React app, I usually start by managing a theme state at a global level, so the whole app can access it. This can be done with React Context or a state library like Zustand.

 

Then I store the user’s preference in localStorage, so when they refresh the page or come back later, the theme is still remembered.

 

For switching themes, I usually add a toggle button that updates the global theme state.

 

For styling, I prefer using CSS variables or a solution like Tailwind CSS. For example, with Tailwind I can use the dark class strategy, where I just add or remove a dark class on the root element, and all components automatically switch styles.

 

So overall, it’s basically: keep a global theme state, persist it in storage, and use CSS or a styling system that can react to that theme.

 

 

8、how do you prevent XSS(Cross-Site Scripting) in frontend apps?

关键词拆解:

  1. XSS (Cross-Site Scripting)

    • 一种常见的前端安全漏洞,攻击者可以注入恶意脚本到网页,执行在其他用户浏览器中。
    • 可能导致 cookie泄露、用户数据被篡改、劫持会话 等。
  2. Frontend apps

    • 前端应用(React / Vue / Angular 等),主要是 浏览器端防护

核心考点:

拆解小问题:

  1. 为什么会发生 XSS?

    • 用户输入未经处理直接插入到 DOM → 执行脚本
  2. 前端可以做什么?

    • 不要插入未处理的 HTML
    • 框架的自动转义机制
    • 对必须插入的 HTML 做 清理/过滤
  3. 可用工具 / 方法?

    • React 自动转义 {userInput}
    • dangerouslySetInnerHTML + DOMPurify
    • 禁用 eval()
    • 内容安全策略 (CSP)

To prevent XSS in frontend apps, I usually think in terms of layers of protection.

First, in React, I rely on its default behavior, because React automatically escapes values in JSX. So in most cases, XSS is already prevented by default.

The main risk comes when we use dangerouslySetInnerHTML. I try to avoid it as much as possible. If I really need it, I sanitize the content first using something like DOMPurify to make sure no scripts can be injected.

 

Second, I’m careful with user-generated URLs. For example, I always validate links and only allow safe protocols like https, so users can’t inject something like javascript:.

 

Third, on the server or deployment side, I like to use a Content Security Policy. That way, even if something slips through, the browser will block unsafe scripts from running.

 

And finally, I also keep dependencies updated and check for known vulnerabilities, just to reduce risk from third-party libraries.

So overall, I think of it as: React handles most of it by default, I sanitize risky inputs when needed, and I use CSP as a safety net.

更短记忆版(面试快答)

React already escapes content by default, so that’s the first protection. I avoid dangerouslySetInnerHTML, or sanitize it with DOMPurify if needed. I validate user URLs to prevent javascript: injection. I also use CSP to block unsafe scripts at the browser level. Overall, it’s about layering defenses.

 

 

9、how do you handle offline/online state gracefully in react with service workers?

1️⃣ 题目关键词

  1. Offline/Online state

    • 意思是用户的网络状态:在线(online)还是离线(offline)。就好像discord、reddit这些网站,用户登录之后,会显示鲜活的头像,如果用户网断了,那么头像就显示黑白色。
    • 你的应用需要知道用户是在线还是离线,并作出对应处理。
  2. Gracefully

    • 不只是知道状态,还要让用户体验顺畅。
    • 例如:显示提示、缓存数据、避免应用崩溃。
  3. React

    • 说明你需要在 React 组件里管理这个状态。
    • 可能涉及 stateContextRedux
  4. Service Workers

    • 浏览器的一种后台脚本,用来缓存资源和数据,实现 离线功能
    • 它允许你的应用在没有网络时仍然能运行一部分功能。

2️⃣ 拆解后的思路

你可以把题目拆解成三个小问题:

(A) 如何在 React 中检测在线/离线状态?

(B) 如何用 Service Worker 支持离线功能?

(C) 如何在重新上线时同步数据?

3️⃣ 组合成回答框架

  1. 检测状态navigator.onLine + online/offline 事件
  2. 更新 UI → 显示横幅、禁用某些功能、提示用户
  3. 离线功能 → Service Worker 缓存静态资源和 API 数据
  4. 重新上线同步 → background sync 或手动发送缓存的请求

老师的要点:

1、I will use navigator.onLine API provided by the browser, to detect network status. And listen to the online and offline events.

2、use service workers to cache critical assets and API responses.

 

To handle offline and online states in a React app, I usually combine browser APIs with a service worker.

 

First, on the frontend, I use navigator.onLine and listen to the online and offline events. I store this status in a global state like Context or a store, so the whole app can react to it. For example, I can show a small banner when the user goes offline or comes back online.

 

Then, I use a Service Worker to make the app work offline. It helps cache static assets and sometimes API responses, so the app can still load even without network.

 

For more advanced cases, I can also queue user actions while offline, and when the user is back online, I sync those requests to the server.

 

So overall, it’s basically: detect network status on the client, update the UI, and use a service worker to provide offline caching and optional syncing.

 

 

 

10、Production is not getting the latest deployed update unless in incognito.How do you solve this?

关键词拆解:

  1. Production is not getting the latest update

    • 用户在生产环境访问网站时,看到的仍是旧版本。
    • 说明前端部署了新版本,但浏览器加载的是缓存的旧文件。
  2. Unless in incognito

    • 这里的隐身模式,指的是浏览器的无痕模式窗口
    • 在隐身模式下正常显示最新版本
    • 隐身模式通常不会使用浏览器缓存或 Service Worker 缓存 → 问题在 缓存策略

核心考点:

拆解小问题:

  1. 为什么普通用户看到旧版本?

    • 浏览器缓存旧 JS/CSS 文件,比如说打包后的main.js,这个文件名没有变化的话,浏览器不会默认获取新的。
    • CDN 缓存旧文件
    • Service Worker 缓存旧资源
  2. 为什么隐身模式正常?

    • 隐身模式不会使用旧缓存 → 能直接获取最新资源
  3. 如何解决?

    • 强制浏览器/用户获取最新文件,Use content hashing for JS/CSS filenames in the build process
    • 设置正确的 HTTP 缓存策略
    • 或在 Service Worker 中处理缓存更新

简要回答:

This is usually a cache issue. If production works in incognito but not in a normal tab, it almost always means the browser is loading an old version from cache.

 

To fix it, I usually look at three things.

First, I make sure the build uses hashed file names for JS and CSS. So when the code changes, the filename changes too, and the browser is forced to download the new version.

 

Second, I check the caching rules for index.html. This file should not be heavily cached, because it points to all the updated assets. So I usually set it to something like no-cache, so the browser always checks for a new version.

 

Third, if the app uses a service worker, I make sure it’s handled properly. Sometimes the old service worker keeps serving cached files. In that case, I update the service worker logic so it can detect a new version and refresh or replace the old cache.

 

So overall, the idea is: let static assets be cached safely with hashes, but make sure the entry HTML and service worker always stay up to date.